home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 June / PersonalComputerWorld-June2009-CoverdiscCD.iso / Software / Freeware / Firebug 1.3.3 / firebug-1.3.3-fx.xpi / content / firebug / tabContext.js < prev    next >
Encoding:
JavaScript  |  2009-02-19  |  11.2 KB  |  387 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. // ************************************************************************************************
  6. // Constants
  7.  
  8. const throttleTimeWindow = 200;
  9. const throttleMessageLimit = 30;
  10. const throttleInterval = 30;
  11. const throttleFlushCount = 20;
  12.  
  13. const refreshDelay = 300;
  14.  
  15. // ************************************************************************************************
  16.  
  17. Firebug.TabContext = function(win, browser, chrome, persistedState)
  18. {
  19.     this.window = win;
  20.     this.browser = browser;
  21.     this.persistedState = persistedState;
  22.  
  23.     this.chrome = chrome;
  24.     this.originalChrome = FirebugChrome;
  25.     if (chrome != FirebugChrome)
  26.     {
  27.         this.detached = true;
  28.         this.externalChrome = chrome;
  29.     }
  30.  
  31.     this.windows = [];
  32.     this.panelMap = {};
  33.     this.sidePanelNames = {};
  34.     this.sourceFileMap = {};
  35.  
  36.     // New nsITraceableChannel interface (introduced in FF3.0.3) makes possible 
  37.     // to re-implement source-cache so, it solves the double-load problem. 
  38.     // Anyway, keep the previous cache implementation for backward compatibility 
  39.     // (with Firefox 3.0.2 and lower)    
  40.     if (Components.interfaces.nsITraceableChannel)
  41.         this.sourceCache = new Firebug.TabCache(win, this);
  42.     else
  43.         this.sourceCache = new Firebug.SourceCache(win, this);
  44. };
  45.  
  46. Firebug.TabContext.prototype =
  47. {
  48.     reattach: function(chrome)
  49.     {
  50.         var oldChrome = this.chrome;
  51.         this.chrome = chrome;
  52.  
  53.         for (var panelName in this.panelMap)
  54.         {
  55.             var panel = this.panelMap[panelName];
  56.             panel.detach(oldChrome, chrome);
  57.             panel.invalid = true;
  58.  
  59.             var panelNode = panel.panelNode;
  60.             if (panelNode && panelNode.parentNode)
  61.                 panelNode.parentNode.removeChild(panelNode);
  62.         }
  63.     },
  64.  
  65.     destroy: function(state)
  66.     {
  67.         if (this.timeouts)
  68.         {
  69.             for (var timeout in this.timeouts)
  70.                 clearTimeout(timeout);
  71.         }
  72.  
  73.         if (this.intervals)
  74.         {
  75.             for (var timeout in this.intervals)
  76.                 clearInterval(timeout);
  77.         }
  78.  
  79.         if (this.throttleTimeout)
  80.             clearTimeout(this.throttleTimeout);
  81.  
  82.         state.panelState = {};
  83.  
  84.         // Inherit panelStates that have not been restored yet
  85.         if (this.persistedState)
  86.         {
  87.             for (var panelName in this.persistedState.panelState)
  88.                 state.panelState[panelName] = this.persistedState.panelState[panelName];
  89.         }
  90.  
  91.         for (var panelName in this.panelMap)
  92.         {
  93.             var panel = this.panelMap[panelName];
  94.  
  95.             // Create an object to persist state, re-using old one if it was never restored
  96.             var panelState = panelName in state.panelState ? state.panelState[panelName] : {};
  97.             state.panelState[panelName] = panelState;
  98.  
  99.             // Destroy the panel and allow it to persist extra info to the state object
  100.             panel.destroy(panelState);
  101.  
  102.             // Remove the panel node from the DOM
  103.             var panelNode = panel.panelNode;
  104.             if (panelNode && panelNode.parentNode)
  105.                 panelNode.parentNode.removeChild(panelNode);
  106.         }
  107.  
  108.         for (var name in this)
  109.             delete this[name];
  110.     },
  111.  
  112.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  113.  
  114.     addPanelType: function(url, title, parentPanel)
  115.     {
  116.         url = absoluteURL(url, this.window.location.href);
  117.         if (!url)
  118.         {
  119.             // XXXjoe Need some kind of notification to console that URL is invalid
  120.             throw("addPanelType: url is invalid!");
  121.             return;
  122.         }
  123.  
  124.         if (!this.panelTypes)
  125.         {
  126.             this.panelTypes = [];
  127.             this.panelTypeMap = {};
  128.         }
  129.  
  130.         var name = createPanelName(url);
  131.         while (name in this.panelTypeMap)
  132.             name += "_";
  133.  
  134.         var panelType = createPanelType(name, url, title, parentPanel);
  135.  
  136.         this.panelTypes.push(panelType);
  137.         this.panelTypeMap[name] = panelType;
  138.  
  139.         return panelType;
  140.     },
  141.  
  142.     removePanelType: function(url)
  143.     {
  144.         // NYI
  145.     },
  146.  
  147.     getPanel: function(panelName, noCreate)
  148.     {
  149.         var panelType = Firebug.getPanelType(panelName);
  150.         if (!panelType && this.panelTypeMap)
  151.             panelType = this.panelTypeMap[panelName];  // context local panelType
  152.         //if (FBTrace.DBG_PANELS)                                                                                       /*@expore*/
  153.         //    FBTrace.sysout("tabContext.getPanel name="+panelName+" noCreate="+noCreate+" panelType="+(panelType?panelType.prototype.name:"null")+"\n");  /*@expore*/
  154.         if (panelType)
  155.             return this.getPanelByType(panelType, noCreate);
  156.     },
  157.  
  158.     getPanelByType: function(panelType, noCreate)
  159.     {
  160.         if (!panelType || !this.panelMap)
  161.             return null;
  162.  
  163.         var panelName = panelType.prototype.name;
  164.         if ( this.panelMap.hasOwnProperty(panelName) )
  165.         {
  166.             var panel = this.panelMap[panelName];
  167.             //if (FBTrace.DBG_PANELS)                                                                                   /*@explore*/
  168.             //    FBTrace.sysout("tabContext.getPanelByType panel in panelMap, .invalid="+panel.invalid+"\n");           /*@explore*/
  169.             if (panel.invalid)
  170.             {
  171.                 var doc = this.chrome.getPanelDocument(panelType);
  172.                 panel.reattach(doc);
  173.                 delete panel.invalid;
  174.             }
  175.  
  176.             return panel;
  177.         }
  178.         else if (!noCreate)
  179.         {
  180.             //if (FBTrace.DBG_PANELS) FBTrace.sysout("tabContext.getPanelByType panel NOT in panelMap\n");              /*@explore*/
  181.             var panel = new panelType();  // This is why panels are defined by prototype inheritance
  182.             var doc = this.chrome.getPanelDocument(panelType);
  183.             panel.initialize(this, doc);
  184.  
  185.             return this.panelMap[panel.name] = panel;
  186.         }
  187.     },
  188.  
  189.     setPanel: function(panelName, panel)  // allows a panel from one context to be used in other contexts.
  190.     {
  191.         this.panelMap[panel.name] = panel;
  192.     },
  193.     
  194.     invalidatePanels: function()
  195.     {
  196.         if (!this.invalidPanels)
  197.             this.invalidPanels = {};
  198.  
  199.         for (var i = 0; i < arguments.length; ++i)
  200.         {
  201.             var panelName = arguments[i];
  202.             var panel = this.getPanel(panelName, true);
  203.             if (panel && !panel.noRefresh)
  204.                 this.invalidPanels[panelName] = 1;
  205.         }
  206.  
  207.         if (this.refreshTimeout)
  208.         {
  209.             this.clearTimeout(this.refreshTimeout);
  210.             delete this.refreshTimeout;
  211.         }
  212.  
  213.         this.refreshTimeout = this.setTimeout(bindFixed(function()
  214.         {
  215.             var invalids = [];
  216.  
  217.             for (var panelName in this.invalidPanels)
  218.             {
  219.                 var panel = this.getPanel(panelName, true);
  220.                 if (panel)
  221.                 {
  222.                     if (panel.visible && !panel.editing)
  223.                         panel.refresh();
  224.                     else
  225.                         panel.needsRefresh = true;
  226.  
  227.                     // If the panel is being edited, we'll keep trying to
  228.                     // refresh it until editing is done
  229.                     if (panel.editing)
  230.                         invalids.push(panelName);
  231.                 }
  232.             }
  233.  
  234.             delete this.invalidPanels;
  235.             delete this.refreshTimeout;
  236.  
  237.             // Keep looping until every tab is valid
  238.             if (invalids.length)
  239.                 this.invalidatePanels.apply(this, invalids);
  240.         }, this), refreshDelay);
  241.     },
  242.  
  243.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  244.  
  245.     setTimeout: function()
  246.     {
  247.         var timeout = setTimeout.apply(top, arguments);
  248.  
  249.         if (!this.timeouts)
  250.             this.timeouts = {};
  251.  
  252.         this.timeouts[timeout] = 1;
  253.  
  254.         return timeout;
  255.     },
  256.  
  257.     clearTimeout: function(timeout)
  258.     {
  259.         clearTimeout(timeout);
  260.  
  261.         if (this.timeouts)
  262.             delete this.timeouts[timeout];
  263.     },
  264.  
  265.     setInterval: function()
  266.     {
  267.         var timeout = setInterval.apply(top, arguments);
  268.  
  269.         if (!this.intervals)
  270.             this.intervals = {};
  271.  
  272.         this.intervals[timeout] = 1;
  273.  
  274.         return timeout;
  275.     },
  276.  
  277.     clearInterval: function(timeout)
  278.     {
  279.         clearInterval(timeout);
  280.  
  281.         if (this.intervals)
  282.             delete this.intervals[timeout];
  283.     },
  284.  
  285.     delay: function(message, object)
  286.     {
  287.         this.throttle(message, object, null, true);
  288.     },
  289.  
  290.     throttle: function(message, object, args, forceDelay)
  291.     {
  292.         if (!this.throttleInit)
  293.         {
  294.             this.throttleBuildup = 0;
  295.             this.throttleQueue = [];
  296.             this.throttleTimeout = 0;
  297.             this.lastMessageTime = 0;
  298.             this.throttleInit = true;
  299.         }
  300.  
  301.         if (!forceDelay)
  302.         {
  303.             if (!Firebug.throttleMessages)
  304.             {
  305.                 message.apply(object, args);
  306.                 return false;
  307.             }
  308.  
  309.             // Count how many messages have been logged during the throttle period
  310.             var logTime = new Date().getTime();
  311.             if (logTime - this.lastMessageTime < throttleTimeWindow)
  312.                 ++this.throttleBuildup;
  313.             else
  314.                 this.throttleBuildup = 0;
  315.  
  316.             this.lastMessageTime = logTime;
  317.  
  318.             // If the throttle limit has been passed, enqueue the message to be logged later on a timer,
  319.             // otherwise just execute it now
  320.             if (!this.throttleQueue.length && this.throttleBuildup <= throttleMessageLimit)
  321.             {
  322.                 message.apply(object, args);
  323.                 return false;
  324.             }
  325.         }
  326.  
  327.         this.throttleQueue.push(message, object, args);
  328.  
  329.         if (this.throttleTimeout)
  330.             this.clearTimeout(this.throttleTimeout);
  331.  
  332.         var self = this;
  333.         this.throttleTimeout =
  334.             this.setTimeout(function() { self.flushThrottleQueue(); }, throttleInterval);
  335.         return true;
  336.     },
  337.  
  338.     flushThrottleQueue: function()
  339.     {
  340.         var queue = this.throttleQueue;
  341.  
  342.         var max = throttleFlushCount * 3;
  343.         if (max > queue.length)
  344.             max = queue.length;
  345.  
  346.         for (var i = 0; i < max; i += 3)
  347.             queue[i].apply(queue[i+1], queue[i+2]);
  348.  
  349.         queue.splice(0, throttleFlushCount*3);
  350.  
  351.         if (queue.length)
  352.         {
  353.             var self = this;
  354.             this.throttleTimeout =
  355.                 this.setTimeout(function f() { self.flushThrottleQueue(); }, throttleInterval);
  356.         }
  357.         else
  358.             this.throttleTimeout = 0;
  359.     }
  360. };
  361.  
  362. // ************************************************************************************************
  363. // Local Helpers
  364.  
  365. function createPanelType(name, url, title, parentPanel)
  366. {
  367.     var panelType = new Function("");
  368.     panelType.prototype = extend(new Firebug.PluginPanel(),
  369.     {
  370.         name: name,
  371.         url: url,
  372.         title: title ? title : "...",
  373.         parentPanel: parentPanel
  374.     });
  375.  
  376.     return panelType;
  377. }
  378.  
  379. function createPanelName(url)
  380. {
  381.     return url.replace(/[:\\\/\s\.\?\=\&\~]/g, "_");
  382. }
  383.  
  384. // ************************************************************************************************
  385.  
  386. }});
  387.